package Participants.CapitoGuye;

// Pour l'interopérabilité: il faut une représentation commune des coups!
import Othello.Move;

public class Joueur extends Othello.Joueur {

    /*------------------------------------------------------------------*\
    |*							Constructeurs							*|
    \*------------------------------------------------------------------*/
    public Joueur(int depth, int playerID) {
        super(depth, playerID); // playerID: 0 = blanc, 1 = noir
        world = new World(size);
        world.nombrePasse = playerID*playerID-1;
        JOUEUR_ACTUEL = playerID;
        Joueur.DEPTH = depth;
        Joueur.PLAYERID = playerID;
    }

    /*------------------------------------------------------------------*\
    |*							Methodes Public							*|
    \*------------------------------------------------------------------*/
    // Méthode appelée à chaque fois que vous devez jouer un coup.
    // Move est le coup joué par l'adversaire
    @Override
    public Move nextPlay(Move move) {
        //=================ADVERSAIRE==================//
        Move result = null;
        JOUEUR_ACTUEL = adversaire();
        // Contrôle le coup de l'adversaire
        if (move != null) {
            //Mettre à jour notre représentation du monde avec le coup de l'adversaire
            world.updateWorld(move);
            System.out.println("Apres avoir jouer le coup(" + move.i + ";" + move.j + ") pour le joueur: " + Joueur.JOUEUR_ACTUEL + "\n" + world);
            world.nombrePasse++;
        }
        world.updateEtatPartie();

        //=================NOUS========================//
        TreeNode root = new TreeNode(world);

        Coup coup;
//                if(root.getCoupJouable().isEmpty()){
//                    JOUEUR_ACTUEL = inverseJoueur();
//                    coup = new Coup(0, null);
//                }else if(root.getCoupJouable().size()==1){
//                    JOUEUR_ACTUEL = inverseJoueur();
//                    coup = new Coup(0, new Move(root.getCoupJouable().get(0).getI(),root.getCoupJouable().get(0).getJ()));
//                }else{
        coup = alphaBeta(root, DEPTH, 1, Integer.MAX_VALUE);
//                }
        result = coup.getCoup();

        // Controle que notre prochain coup est valide
        if (result != null) {
            //Mettre à jour notre représentation du monde après avoir choisi notre coup
            world.updateWorld(result);
            System.out.println("Apres avoir jouer le coup(" + result.i + ";" + result.j + ") pour le joueur: " + JOUEUR_ACTUEL + "\n" + world);
        } else {
            world.nombrePasse--;
            System.out.println("Perimetre jouable pour le joueur:" + JOUEUR_ACTUEL + "\n" + world.getListPerimetreJouable());
            System.out.println("Coup jouable \n" + root.getCoupJouable());
        }

        // Retourne notre coup
        return result;
    }

    /*------------------------------*\
    |*				Get				*|
    \*------------------------------*/
    public World getWorld() {
        return world;
    }

    /*------------------------------*\
    |*			  Static			*|
    \*------------------------------*/
    public static int inverseJoueur() {
        return (JOUEUR_ACTUEL + 1) % 2;
    }

    /*------------------------------------------------------------------*\
    |*							Methodes Private						*|
    \*------------------------------------------------------------------*/
    private int adversaire() {
        return (playerID + 1) % 2;
    }

    private Coup alphaBeta(TreeNode root, int depth, int minOrMax, int valeurCoupParent) {


        if (depth == 0 || root.isFinal()) {
            return new Coup(root.situationDuNoeud());
        }

        int temp = (JOUEUR_ACTUEL + 1) % 2;
        JOUEUR_ACTUEL = temp;
        int optVal = minOrMax * -Integer.MAX_VALUE;
        Move optOp = null;
        if (depth == DEPTH) {
            System.out.println("Tout les coups " + depth + ": " + world.getCoupsJouable());
        }
        for (Case coupJouable : world.getCoupsJouable()) {
            TreeNode newNode = root.appliqueCoupVirtuel(coupJouable, root.getWorld().cloneOf());
            Coup coup = alphaBeta(newNode, depth - 1, -minOrMax, optVal);
            JOUEUR_ACTUEL = temp;
            if (depth == DEPTH) {
                System.out.println("Case joue " + depth + ": " + coupJouable + " val: " + coup.getValeur());
            }

            if (coup.getValeur() * minOrMax > optVal * minOrMax) {
                optVal = coup.getValeur();
                optOp = new Move(coupJouable.getI(), coupJouable.getJ());

                if (optVal * minOrMax > valeurCoupParent * minOrMax) {
//                    System.out.println("Coupe "+depth+": "+optOp+" optval:"+optVal+" couparent:"+valeurCoupParent);
                    break;
                }
            }
        }
        return new Coup(optVal, optOp);
    }

    /*------------------------------------------------------------------*\
    |*							Attributs Private						*|
    \*------------------------------------------------------------------*/
    private World world;

    /*------------------------------*\
    |*			  Static			*|
    \*------------------------------*/
    public static int JOUEUR_ACTUEL;
    public static int DEPTH;
    public static int PLAYERID;
}
